/**
 * @project weixin
 * @author ddc <jncpp@qq.com>
 */

var EVENT_EMITTER = require("events").EventEmitter;
var SHA1 = require("crypto").createHash('sha1');
var UTIL = require("util");
var HTTP = require("http");
var XML2JS = require("xml2js").parseString;

var LOGGER = require("./config.js").Logger;
/**
 * 微信类,处理消息和发送消息
 *
 * @constructor
 */
function Weixin() {}
UTIL.inherits(Weixin, EVENT_EMITTER);        // 继承自EventEmitter的原型

exports.Weixin = Weixin;

/**
 * 全局配置数据
 *
 * @namespace
 * @name config
 */
Weixin.prototype.config = {
    /**
     * Weixin Token
     *
     * @type String
     * @memberof config
     */
    token: "kingddc314",
    /**
     * 关注后给用户发送的文本消息
     *
     * @type String
     * @memberof config
     */
    subscribeMsg: "欢迎关注wp8，请回复任意文字，机器人能自动回复的哟！/::$/::$\n" +
        "/::B收听电台回复：\n" +
            "\t\t电台\n" +
            "\t\tfm\n" +
        "/:8-)搜索歌曲回复v加任意歌名或歌手关键字：\n" +
            "\t\tv光辉岁月\n" +
            "\t\tv张杰 领悟\n" +
            "\t\tv平凡之路 朴树\n" +
        "/::P更多功能敬请期待.../:,@f/:,@f/:,@f",
    /**
     * 当前订阅号ID
     *
     * @type String
     * @memberof config
     */
    userId: null,
    /**
     * Weixin内部自定义的错误消息，一般用于结果查找不到情况
     *
     * @type String
     * @memberof config
     */
    errorMsg: {
        meessage: "unknown error",
        code: 9527
    },
    /**
     * 百度音乐中的音质码率设置，支持128和320
     *
     * @type String
     * @memberof config
     */
    rate: "&rate=128",
    /**
     * 百度音乐电台的频道key值和名称
     *
     * @type Array
     * @memberof config
     */
    fmList: [
        { key: "public_tuijian_winter", name: "温暖冬日" },
        { key: "public_tuijian_zhongguohaoshengyin", name: "中国好声音" },
        { key: "public_tuijian_rege", name: "热歌" },
        { key: "public_tuijian_ktv", name: "KTV金曲" },
        { key: "public_tuijian_billboard", name: "Billboard" },
        { key: "public_tuijian_chengmingqu", name: "成名曲" },
        { key: "public_tuijian_wangluo", name: "网络红歌" },
        { key: "public_tuijian_kaiche", name: "开车" },
        { key: "public_tuijian_yingshi", name: "影视" },
        { key: "public_tuijian_suibiantingting", name: "随便听听" },

        { key: "public_shiguang_jingdianlaoge", name: "经典老歌" },
        { key: "public_shiguang_70hou", name: "70后" },
        { key: "public_shiguang_80hou", name: "80后" },
        { key: "public_shiguang_90hou", name: "90后" },
        { key: "public_shiguang_xinge", name: "火爆新歌" }
    ],
    /**
     * 关注用户列表，包含每个用户的状态和数据, ["default"]为默认数据
     *
     * @type Object
     * @memberof config
     */
    userList: {
        "default": {
            status: 0,   // 状态0为默认状态，状态1为用户输入音乐搜索，状态2为用户输入电台列表。。。然后等待输入数字进行选择
            data: [],    // 状态改变携带的数据
            fmKey: "public_tuijian_suibiantingting"    // 频道
        }
    }
};

/**
 * 获取用户状态和数据
 *
 * @param  {String} user
 * @return {Object}
 */
Weixin.prototype.getUser = function(user){
    var self = this;
    // 不能对undefined进行任何运算
    if(!self.config.userList[user]){
        self.config.userList[user] = self.config.userList["default"];
    }
    return self.config.userList[user];
};

/**
 * 设置用户状态和数据
 *
 * @param  {String} user
 * @param  {Number} status     - 0,默认状态 1,音乐选择状态 2,电台选择状态 3,公交站点选择状态
 * @param  {Array } data
 * @param  {String} fmKey      - fmKey为空时使用默认值
 */
Weixin.prototype.setUser = function(user, status, data, fmKey){
    var self = this;
    if(!fmKey){
        if(self.config.userList[user]){
            fmKey = self.config.userList[user].fmKey;
        }else{
            fmKey = self.config.userList["default"].fmKey;
        }
    }
    self.config.userList[user] = {
        status: status,
        data: data,
        fmKey: fmKey
    };
    LOGGER.trace("status:", self.config.userList[user].status);
};

/**
 * 删除用户
 *
 * @param  {String} user
 */
Weixin.prototype.delUser = function(user){
    var self = this;
    self.config.userList[user] = null;
};

/**
 * 重置用户状态和用户数据
 *
 * @param  {String} user
 */
Weixin.prototype.resetUser = function(user){
    var self = this;
    self.setUser(user, 0, null, null);
};

/**
 * 检查微信接口申请
 *
 * @param  {Object} value
 * @return {Boolean}
 */
Weixin.prototype.checkSignature = function (value) {
    var arr = [this.config.token, value.timestamp, value.nonce];
    arr.sort();
    var check_str = SHA1.update(arr.join("")).digest('hex');
    return (check_str == value.signature);
};

/**
 * 解析并处理接收到的微信消息
 *
 * @param {Object} body
 * @param {Object} response
 */
Weixin.prototype.parse = function (body, response) {
    var self = this;

    var date = new Date();
    date.setTime(body.CreateTime[0] * 1000); // setTime是向1970添加毫秒,所以此处需要乘以1000
    // 解析接收消息
    var msgType = body.MsgType[0] ? body.MsgType[0] : "text";
    switch (msgType) {
        case "text":{
            LOGGER.trace(UTIL.format("[%s] [%s] %s:\n\t%s",
                body.MsgType[0], date.toString(), body.FromUserName[0], body.Content[0]));
            self.parseTextMsg(body.FromUserName[0], body.Content[0], response);
            break;
        }
        case "image":{
            LOGGER.trace(UTIL.format("[%s] [%s] %s:\n\t%s\n\t",
                body.MsgType[0], date.toString(), body.FromUserName[0], body.PicUrl[0]), body.MediaId[0]);
            self.parseImageMsg(body.FromUserName[0], body.MediaId[0], response);
            break;
        }
        case "voice":{
            LOGGER.trace(UTIL.format("[%s] [%s] %s:\n\t%s",
                body.MsgType[0], date.toString(), body.FromUserName[0], body.MediaId[0]));
            self.parseVoiceMsg(body.FromUserName[0], body.MediaId[0], response);
            break;
        }
        case "video":
            break;
        case "location":
            break;
        case "link":
            break;
        case "event":{
            // 处理订阅或取消订阅事件
            LOGGER.trace(UTIL.format("[%s] [%s] %s: %s",
                body.MsgType[0], date.toString(), body.FromUserName[0], body.Event[0]));
            self.parseEventMsg(body.FromUserName[0], body.Event[0], response);
            break;
        }
        default :
            break;
    }
};

/**
 * 解析文本消息
 *
 * @param {String} toUser
 * @param {String} content
 * @param {Object} response
 */
Weixin.prototype.parseTextMsg = function (toUser, content, response) {
    var self = this;

    // 播放百度音乐电台
    if(content === "电台" || content === "fm" || content === "f")
    {
        self.processFmMsg(toUser, response);
    }else if(content === "电台列表" || content === "fmlist" || content === "fl") {
        self.processFmList(toUser, response);
    }else{
        // 使用百度音乐搜索，格式如"v领悟 张杰"
        var match = content.match(new RegExp("v(.+)"));
        if(match){
            var title = match[1];
            self.processMusicSearch(toUser, title, response);
        }else{
            // 是**路的线路查询
            // 这里先匹配**路,再匹配**
            var match2 = content.match(new RegExp("\\b(\\d+)路"));
            if(match2){
                self.processBusSearch(toUser, match2[1], false, response);
            }else{
                // 数字选择结果
                match2 = content.match(new RegExp("\\b(\\d+)"));
                if(match2) {
                    self.processChoiceResult(toUser, self.getUser(toUser).status, Number(match2[1]), response);
                }else{
                    // 使用小黄鸡接口
                    //self.processXiaohuangji(toUser, content, response);
                    // 使用百度新闻搜索接口
                    self.processNewsSearch(toUser, content, response);
                }
            }
        }
    }
};

/**
 * 处理文字消息中的电台消息
 *
 * @param {String} toUser
 * @param {Object} response
 */
Weixin.prototype.processFmMsg = function(toUser, response){
    var self = this;
    // 发送FM歌曲列表的图文消息
    var sendFmSongsByPlayList = function(){
        if(self.playlist.length >= 5){
            var items = [];
            for(var i = 0; i <5; i++){
                var songInfo = self.playlist.shift();
                var str_size = UTIL.format(" [%dM]", Math.round(songInfo.size / 1024 / 1024 * 100) / 100);
                var str_time = UTIL.format(" [%d:%d]", Math.floor(songInfo.time / 60), songInfo.time % 60);
                var str_hq = songInfo.rate == 320 ? " [HQ]" : "";
                items.push({
                    title: songInfo.songName + " - " + songInfo.artistName + str_hq,
                    desc: songInfo.albumName + str_size + str_time,
                    picUrl: songInfo.songPicRadio,
                    url: "http://music.baidu.com/song/" + songInfo.songId
                });
            }
            self.sendNewsMsg({
                toUser: toUser,
                fromUser: self.config.userId,
                items: items,
                response: response
            });
        }
    };
    // 电台消息通过图文发送
    if(!self.playlist || self.playlist.length < 5){
        self.getBaiduFmPlayList(toUser, function(err, songs) {
            if (!err && songs) {
                LOGGER.info(UTIL.format("get new douban.fm playlist [%d]", songs.length));
                self.playlist = songs;
                sendFmSongsByPlayList();
            }
        });
    }else{
        sendFmSongsByPlayList();
    }
};

/**
 * 处理文本消息中的电台列表消息
 *
 * @param {String} toUser
 * @param {Object} response
 */
Weixin.prototype.processFmList = function(toUser, response){
    var self = this;
    var str = '电台列表如下，回复数字选择相应频道：\n';
    for (var i in self.config.fmList) {
        str += UTIL.format("[%d]  %s", Number(i) + 1, // 这里i是string类型,需要转换成number
            self.config.fmList[i].name);
        if(i != self.config.fmList.length - 1){
            str += "\n";
        }
    }
    self.sendTextMsg({
        toUser: toUser,
        fromUser: self.config.userId,
        text: str,
        response: response
    });
    self.setUser(toUser, 2, null, null);
};

/**
 * 处理文本消息中的音乐搜索消息
 *
 * @param {String} toUser
 * @param {String} title
 * @param {Object} response
 */
Weixin.prototype.processMusicSearch = function(toUser, title, response){
    var self = this;
    self.getBaiduMusic(title, function(err, result){
        if (!err) {
            var str = '搜索"' + title + '"结果如下，回复数字选择播放：\n';
            for (var i in result) {
                if(Number(i) + 1 > 9){
                    break;
                }
                str += UTIL.format("[%d] %s", Number(i) + 1, // 这里i是string类型,需要转换成number
                        result[i].songName + " - " + result[i].artistName);
                if(Number(i) + 1 < 9 && i != result.length - 1){
                    str += "\n";
                }
            }
            self.sendTextMsg({
                toUser: toUser,
                fromUser: self.config.userId,
                text: str,
                response: response
            });
            self.setUser(toUser, 1, result, null);
        }else{
            self.processXiaohuangji(toUser, title, response);
        }
    });
};

/**
 * 处理文本消息中的公交线路搜索
 *
 * @param {String} toUser
 * @param {String} xianlu
 * @param {Boolean} isBack
 * @param {Object} response
 */
Weixin.prototype.processBusSearch = function(toUser, xianlu, isBack, response){
    var self = this;
    self.getBusInfo(xianlu, isBack, function(err, list){
        if(err || list.result.length === 0){
            self.sendTextMsg({
                toUser: toUser,
                fromUser: self.config.userId,
                text: "公交线路[" + xianlu + "]查询结果不存在,请检查是否拼写有误",
                response: response
            });
        }else{
            var text = UTIL.format("%d路\n%s(%s)\n->\n%s(%s)\n\n换向请回复0\n\n", xianlu,
            list.begin.name, list.begin.time, list.end.name, list.end.time);
            for(var i in list.result){
                var index = list.result[i].index.length === 1 ? ("  " + list.result[i].index) : list.result[i].index;
                text += (index + ":  " + list.result[i].name + "\n");
            }
            self.sendTextMsg({
                toUser: toUser,
                fromUser: self.config.userId,
                text: text,
                response: response
            });
            self.setUser(toUser, 3, list, null);
        }
    });
};

/**
 * 处理文本消息中发生数字选择结果的消息
 *
 * @param {String} toUser
 * @param {Number} status
 * @param {String | Number} number
 * @param {Object} response
 */
Weixin.prototype.processChoiceResult = function(toUser, status, number, response){
    var self = this;
    switch(status){
        case 1 :{
            // 处理当搜索音乐后，等待用户选择的状态
            var result = self.getUser(toUser).data[Number(number) - 1];
            if(result){
                var str_size = UTIL.format(" [%dM]", Math.round(result.size / 1024 / 1024 * 100) / 100);
                var str_time = UTIL.format(" [%d:%d]", Math.floor(result.time / 60), result.time % 60);
                var str_hq = result.rate == 320 ? " [HQ]" : "";
                self.sendMusicMsg({
                    toUser: toUser,
                    fromUser: self.config.userId,
                    title: result.songName + " - " + result.artistName + str_hq,
                    desc: result.albumName + str_size + str_time,
                    url: result.songLink,
                    urlHD: result.songLink,
                    response: response
                });
                LOGGER.trace(result.songName + " - " + result.artistName, result.albumName);
                LOGGER.trace(result.songLink);
            }else{
                self.processXiaohuangji(toUser, number, response);
            }
            break;
        }
        case 2:{
            // 处理当发送电台列表后，等待用户选择的状态
            var result = self.config.fmList[Number(number) - 1];
            if(result){
                self.setUser(toUser, 2, null, result.key);   // 状态不变
                self.playlist = null;       // 清空歌曲列表
                self.processFmMsg(toUser, response);
            }else{
                self.processXiaohuangji(toUser, number, response);
            }
            break;
        }
        case 3:{
            // 处理当发送线路后，等待用户选择线路站点
            var list = self.getUser(toUser).data;
            if(Number(number) === 0){
                self.processBusSearch(toUser, list.id, true, response);
            }else if(Number(number) <= list.result.length){
                self.getBusArriveInfo(list.id, list.result[Number(number) - 1].id, function(err, body){
                    var text = "";
                    if(err){
                        text = "未知错误,请重试";
                    }else{
                        var res = JSON.parse(body);
                        if(res.status === "101"){
                            for(var i in res.busList){
                                text += UTIL.format("距今%s站，在%s，预计%s分钟到站\n",
                                    res.busList[i].lineDist, res.busList[i].currentStation, res.busList[i].arriveTime);
                            }
                        }else{
                            LOGGER.trace("bus arrive code: %s", res.status);
                            text = res.resultdes;
                        }
                    }
                    self.sendTextMsg({
                        toUser: toUser,
                        fromUser: self.config.userId,
                        text: text,
                        response: response});
                });
            }else{
                self.processBusSearch(toUser, Number(number), false, response);
            }
            break;
        }
        default :{
            //self.processXiaohuangji(toUser, number, response);
            self.processBusSearch(toUser, number, false, response);
        }
    }
};

/**
 * 处理文本消息中的其他消息，使用小黄鸡自动回复
 *
 * @param {String} toUser
 * @param {String} content
 * @param {Object} response
 */
Weixin.prototype.processXiaohuangji = function (toUser, content, response){
    var self = this;
    // 关键字预处理
    if(content == "wp8"){       // wp8小黄鸡会自动回复垃圾，好吧，和谐一下
        content = "WP8";
    }

    var addUrl = function(msg, url) {
        return UTIL.format("<a href='%s'>%s</a>", url, msg);
    };

    self.getXiaohuangji(content, function(err, msg){
        if(!err){
            // 前置处理
            if(content == "热门微博"){
                msg = addUrl(msg, "http://m.weibo.cn/p/102803");
            }else if(content == "微博"){
                msg = addUrl(msg, "http://m.weibo.cn/");
            }
            self.sendTextMsg({
                toUser: toUser,
                fromUser: self.config.userId,
                text: msg,
                response: response
            });
        }else{
            LOGGER.error("xiaohuangji error:", err);
        }
        self.resetUser(toUser);
    });
};

/**
 * 处理文本消息中的新闻搜索
 *
 * @param {String} toUser
 * @param {String} content
 * @param {Object} response
 */
Weixin.prototype.processNewsSearch = function(toUser, content, response){
    var self = this;
    var addUrl = function(msg, url) {
        return UTIL.format("<a href='%s'>%s</a>", url, msg);
    };
    //http://news.baidu.com/ns?word=%s&tn=news&from=news&cl=2&rn=20&ct=1
    //http://news.baidu.com/ns?ct=1&rn=20&ie=utf-8&rsv_bp=1&sr=0&cl=2&f=8&prevct=no&word=%s&tn=news&inputT=0
    self.get(UTIL.format("http://news.baidu.com/ns?word=%s&tn=news&from=news&cl=2&rn=20&ct=1", content,content), function(err, body){
        if(err){
            self.processXiaohuangji(toUser,content, response);
        }else{
            var reg = new RegExp('<li[\\s\\S]+?' +
                '<a\\s*href="(.+?)"[\\s\\S]+?' +                    // 匹配url
                '>([\\s\\S]+?)</a>[\\s\\S]+?' +                     // 匹配标题
                'class="c-author">&nbsp;([\\s\\S]+?)&nbsp;' +       // 匹配出处
                '([\\s\\S]+?)</span>[\\s\\S]+?' +                   // 匹配时间
                '</li>', "g");
            var result;
            var res = [];
            while ((result = reg.exec(body)) != null) {
                res.push({
                    url: result[1],
                    title: result[2].replace(/[<em>|<\/em>]/g, ""),
                    ref: result[3],
                    time: result[4]
                });
            }
            if(res.length != 0){
                var str = "";
                for(var i in res){
                    if(Number(i) + 1 > 6){
                        break;
                    }
                    str += UTIL.format("[%d] %s\n\t\t[%s %s]", Number(i) + 1,
                        addUrl(res[i].title, res[i].url), res[i].ref, res[i].time
                    );
                    if(Number(i) + 1 < 6 && i != res.length - 1){
                        str += "\n\n";
                    }
                }
                self.sendTextMsg({
                    toUser: toUser,
                    fromUser: self.config.userId,
                    text: str,
                    response: response
                });
                self.resetUser(toUser);
            }else{
                self.processXiaohuangji(toUser,content, response);
            }
        }
    });
};

/**
 * 解析图片消息
 *
 * @param {String} toUser
 * @param {String} mediaId
 * @param {Object} response
 */
Weixin.prototype.parseImageMsg = function (toUser, mediaId, response) {
    var self = this;
    self.sendImageMsg({
        toUser: toUser,
        fromUser: self.config.userId,
        mediaId: mediaId,
        response: response
    });
    self.resetUser(toUser);
};

/**
 * 解析语音消息
 *
 * @param {String} toUser
 * @param {String} mediaId
 * @param {Object} response
 */
Weixin.prototype.parseVoiceMsg = function (toUser, mediaId, response) {
    var self = this;
    self.sendVoiceMsg({
        toUser: toUser,
        fromUser: self.config.userId,
        mediaId: mediaId,
        response: response
    });
    self.resetUser(toUser);
};

/**
 * 解析事件消息
 *
 * @param {String} toUser
 * @param {String} event
 * @param {Object} response
 */
Weixin.prototype.parseEventMsg = function (toUser, event, response) {
    var self = this;
    if(event == "subscribe")
    {
        // 订阅
        self.sendTextMsg({
            toUser: toUser,
            fromUser: self.config.userId,
            text: this.config.subscribeMsg,
            response: response
        });
        self.resetUser(toUser);
    }else if(event == "unsubscribe"){
        // 取消订阅
        response.end();
        self.delUser(toUser);
    }else{
        self.resetUser(toUser);
        response.end();
    }
};

/**
 * 发送文本消息
 *
 * @param {Object} value
 * @example
 * self.sendTextMsg({
 *  toUser: "接收消息用户",
 *  fromUser: "发送者",
 *  text: "文本内容",
 *  response: "http响应对象"
 * })
 */
Weixin.prototype.sendTextMsg = function (value) {
    var createTime = Math.round(Date.now() / 1000);
    var str = UTIL.format("<xml>\
                <ToUserName><![CDATA[%s]]></ToUserName>\
                <FromUserName><![CDATA[%s]]></FromUserName>\
                <CreateTime>%d</CreateTime>\
                <MsgType><![CDATA[text]]></MsgType>\
                <Content><![CDATA[%s]]></Content>\
            </xml>", value.toUser, value.fromUser, createTime, value.text);
    value.response.write(str, "utf8");
    value.response.end();
};

/**
 * 发送音乐消息
 *
 * @param {Object} value
 * @example
 *  self.sendMusicMsg({
 *  toUser: "接收消息用户",
 *  fromUser: "发送者",
 *  title: "音乐标题",
 *  desc: "音乐描述",
 *  url: "音乐链接",
 *  urlHD: "高质量音乐链接,WIFI下优选此链接",
 *  mediaId: "缩略图的媒体ID[可选参数]"
 *  response: "http响应对象"
 * })
 */
Weixin.prototype.sendMusicMsg = function(value){
    var createTime = Math.round(Date.now() / 1000);
    var media_str = "";
    if(value.mediaId){
        media_str = "<ThumbMediaId><![CDATA[" + value.mediaId + "]]></ThumbMediaId>";
    }
    var str = UTIL.format(
        "<xml>\
            <ToUserName><![CDATA[%s]]></ToUserName>\
            <FromUserName><![CDATA[%s]]></FromUserName>\
            <CreateTime>%d</CreateTime>\
            <MsgType><![CDATA[music]]></MsgType>\
            <Music>\
                <Title><![CDATA[%s]]></Title>\
                <Description><![CDATA[%s]]></Description>\
                <MusicUrl><![CDATA[%s]]></MusicUrl>\
                <HQMusicUrl><![CDATA[%s]]></HQMusicUrl>\
                %s\
            </Music>\
        </xml>", value.toUser, value.fromUser, createTime,
        value.title, value.desc, value.url, value.urlHD, media_str
    );
    value.response.write(str, "utf8");
    value.response.end();
};

/**
 * 发送图片消息
 *
 * @param {Object} value
 * @example
 * self.sendImageMsg({
 *  toUser: "接收消息用户",
 *  fromUser: "发送者",
 *  mediaId: "多媒体文件ID",
 *  response: "http响应对象"
 * })
 */
Weixin.prototype.sendImageMsg = function(value){
    var createTime = Math.round(Date.now() / 1000);
    var str = UTIL.format("<xml>\
    <ToUserName><![CDATA[%s]]></ToUserName>\
        <FromUserName><![CDATA[%s]]></FromUserName>\
        <CreateTime>%d</CreateTime>\
        <MsgType><![CDATA[image]]></MsgType>\
        <Image>\
            <MediaId><![CDATA[%s]]></MediaId>\
        </Image>\
    </xml>", value.toUser, value.fromUser, createTime, value.mediaId);
    value.response.write(str, "utf8");
    value.response.end();
};

/**
 * 发送语音消息
 *
 * @param {Object} value
 * @example
 * self.sendVoiceMsg({
 *  toUser: "接收消息用户",
 *  fromUser: "发送者",
 *  mediaId: "多媒体文件ID",
 *  response: "http响应对象"
 * })
 */
Weixin.prototype.sendVoiceMsg = function(value){
    var createTime = Math.round(Date.now() / 1000);
    var str = UTIL.format("<xml>\
        <ToUserName><![CDATA[%s]]></ToUserName>\
        <FromUserName><![CDATA[%s]]></FromUserName>\
        <CreateTime>%d</CreateTime>\
        <MsgType><![CDATA[voice]]></MsgType>\
        <Voice>\
            <MediaId><![CDATA[%s]]></MediaId>\
        </Voice>\
    </xml>", value.toUser, value.fromUser, createTime, value.mediaId);
    value.response.write(str, "utf8");
    value.response.end();
};

/**
 * 发送图文消息
 *
 * @param {Object} value
 * @example
 * self.sendNewsMsg({
 *  toUser: "接收消息用户",
 *  fromUser: "发送者",
 *  items: [
 *      {
 *          title: "标题",
 *          desc: "副标题(描述)",
 *          picUrl: "图片链接",
 *          url: "点击图文消息跳转连接"
 *      },
 *      {
 *          title: "标题",
 *          desc: "副标题(描述)",
 *          picUrl: "图片链接",
 *          url: "点击图文消息跳转连接"
 *      }
 *  ],
 *  response: "http响应对象"
 * })
 */
Weixin.prototype.sendNewsMsg = function(value){
    var createTime = Math.round(Date.now() / 1000);
    var newsItems = "";
    var items = value.items;
    for(var i in items){
        newsItems += UTIL.format("<item>\
            <Title><![CDATA[%s]]></Title>\
            <Description><![CDATA[%s]]></Description>\
            <PicUrl><![CDATA[%s]]></PicUrl>\
            <Url><![CDATA[%s]]></Url>\
        </item>", items[i].title, items[i].desc, items[i].picUrl, items[i].url);
    }
    var str = UTIL.format("<xml>\
    <ToUserName><![CDATA[%s]]></ToUserName>\
        <FromUserName><![CDATA[%s]]></FromUserName>\
        <CreateTime>%d</CreateTime>\
        <MsgType><![CDATA[news]]></MsgType>\
        <ArticleCount>%d</ArticleCount>\
        <Articles>\
            %s\
        </Articles>\
    </xml> ", value.toUser, value.fromUser, createTime, items.length, newsItems);
    value.response.write(str, "utf8");
    value.response.end();
};

/**
 * 获取豆瓣电台列表
 *
 * @param {Function} cb
 * @example
 * self.getDoubanFmPlayList(function(err, resultList){
 * });
 */
Weixin.prototype.getDoubanFmPlayList = function(cb){
    var self = this;
    self.get("http://douban.fm/j/mine/playlist?type=n&pt=5.1&channel=1&pb=64&from=mainsite", function(err, res_body){
        if(err){
            cb(err);
        }else{
            var result = JSON.parse(res_body);
            result.song.shift();   // 忽略第一首歌
            cb(null, result.song);
        }
    });
};

/**
 * 获取百度电台列表
 *
 * @param {String} toUser
 * @param {Function} cb
 * @example
 * self.getBaiduFmPlayList(toUser, function(err, resultList){
 * });
 */
Weixin.prototype.getBaiduFmPlayList = function(toUser, cb){
    var self = this;
    self.get(UTIL.format("http://fm.baidu.com/dev/api/?tn=playlist&id=%s&special=flash&prepend=&format=json", self.getUser(toUser).fmKey), function(err, res_body){
        if(err){
            cb(err);
        }else{
            var result = JSON.parse(res_body);
            for(var i in result.list){
                result.list[i] = result.list[i].id;
            }
            var idlist = result.list.join(",");
            var songinfo = UTIL.format("http://music.baidu.com/data/music/fmlink?songIds=%s&type=mp3%s", idlist, self.config.rate);
            self.get(songinfo, function(err2, res_body2){
                if(err2){
                    cb(err2);
                }else {
                    var result2 = JSON.parse(res_body2);
                    if(result2.errorCode == 22000) {
                        cb(null, result2.data.songList);
                    }else{
                        cb(self.config.errorMsg, null);
                    }
                }
            });
        }
    });
};

/**
 * 获取小黄鸡自动回复结果
 *
 * @param {String} content
 * @param {Function} cb
 * @example
 * self.getXiaohuangji(content, function(err, content){
 * });
 */
Weixin.prototype.getXiaohuangji = function(content, cb) {
    var options = {
        hostname: 'www.xiaohuangji.com',
        path: '/ajax.php',
        method: 'POST',
        headers: {
            "Accept":"*/*",
            "Accept-Encoding":"gzip,deflate,sdch",
            "Accept-Language":"zh-CN,zh;q=0.8",
            "Connection":"keep-alive",
            //"Content-Length":"6",
            "Content-Type":"application/x-www-form-urlencoded",
            //"Cookie":"bdshare_firstime=1407140631155",
            "Host":"www.xiaohuangji.com",
            "Origin":"http://www.xiaohuangji.com",
            "Referer":"http://www.xiaohuangji.com/",
            "User-Agent":"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.114 Safari/537.36",
            "X-Requested-With":"XMLHttpRequest"
        }
    };

    // 发送小黄鸡请求
    var req = HTTP.request(options, function(res){
        res.setEncoding("utf8");
        var res_body = "";
        res.on("data", function(chunk) {
            res_body += chunk;
        });
        res.on("end", function(){
            cb(null, res_body);
        });
        res.on("error", function(err){
            cb(err);
        });
    });
    req.on("error", function(err){
        LOGGER.error("problem with request: ", err.message);
        cb(err);
    });
    // 写入请求主体
    var contents = "para=" + content;
    req.write(contents);
    req.end();
};

/**
 * 获取百度音乐搜索结果
 *
 * @param {String} title
 * @param {Function} cb
 * @example
 * self.getBaiduMusic(title, function(err, resultList){
 * });
 */
Weixin.prototype.getBaiduMusic = function(title, cb){
    var self = this;
    var url = UTIL.format("http://sug.music.baidu.com/info/suggestion?format=json&version=2&from=0&word=%s",
        title);
    self.get(url, function(err, res_body){
        if(err){
            cb(err, null);
        }else{
            var result = JSON.parse(res_body);
            if(result.data.song && result.data.song.length > 0){
                for(var i in result.data.song){
                    result.data.song[i] = result.data.song[i].songid;
                }
                var idlist = result.data.song.join(",");
                self.get("http://ting.baidu.com/data/music/links?songIds=" + idlist + self.config.rate, function(err2, res_body2){
                    if(err2){
                        cb(err2, null);
                    }else{
                        var result2 = JSON.parse(res_body2);
                        if(result2.errorCode == 22000){
                            // 部分链接中带有&src=""需去除才能正常播放
                            for(var i in result2.data.songList){
                                var match = result2.data.songList[i].songLink.match(new RegExp('\\b(.+)&src=.+\\b"'));
                                if(match){
                                    result2.data.songList[i].songLink = match[1];
                                }
                            }
                            cb(null, result2.data.songList);
                        }else{
                            cb(self.config.errorMsg, null);
                        }
                    }
                });
            }else{
                cb(self.config.errorMsg, null);
            }
        }
    });
};

/**
 * 获取线路搜索结果信息
 *
 * @param {Number} xianlu
 * @param {Boolean} isBack     是否是返程线路
 * @param {Function} cb
 * @return {Object}
 * @example
 * self.getBusInfo(xianlu, function(err, resultList){
 * });
 */
Weixin.prototype.getBusInfo = function(xianlu, isBack, cb){
    var self = this;
    var url = UTIL.format("http://www.basbus.cn/m/line?id=%d%s", xianlu, isBack ? "&t=2" : "");
    self.get(url, function(err, body){
        if(err){
            cb(err, null);
        }else{
            var reg = new RegExp('"li_01">(.+?)</li>[\\s\\S]*?"yuanicon">(\\d+)</div>' +
                '[\\s\\S]*?"display:none">(\\d+)</p>', "g");
            var result;
            var list = { id: xianlu, result: []};
            while((result = reg.exec(body)) != null){
                list.result.push({
                    name: result[1],
                    index: result[2],
                    id: result[3]
                })
            }
            reg = new RegExp('"leftspan01">(.+?)</span>[\\s\\S]*?"leftspan02">(.+?)</span>' +
                '[\\s\\S]*?"rightspan01">(.+?)</span>[\\s\\S]*?"rightspan02">(.+?)</span>');
            var match = body.match(reg);
            if(match){
                list.begin = {name: match[1], time: match[2]};
                list.end = {name: match[3], time: match[4]};
            }
            cb(null, list);
        }
    });
};

/**
 * 获取某线路的某站点的距离站点信息
 * @param {String} id
 * @param {String} gps
 * @param {Function} cb
 */
Weixin.prototype.getBusArriveInfo = function(id, gps, cb){
    // 写入请求主体
    var contents = "id=" + id + "&g=" + gps;
    var options = {
        hostname: 'www.basbus.cn',
        path: '/m/station',
        method: 'POST',
        headers: {
            "Accept":"*/*",
            "Accept-Encoding":"gzip,deflate,sdch",
            "Accept-Language":"zh-CN,zh;q=0.8",
            "Cache-Control": "no-cache",
            "Connection":"keep-alive",
            "Content-Length": contents.length,
            "Content-Type":"application/x-www-form-urlencoded; charset=UTF-8",
            "Host":"www.basbus.cn",
            "Origin":"http://www.basbus.cn",
            "Referer":"http://www.basbus.cn/m/line?id=" + id,
            "User-Agent":"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.114 Safari/537.36",
            "X-Requested-With":"XMLHttpRequest"
        }
    };

    // 发送小黄鸡请求
    var req = HTTP.request(options, function(res){
        res.setEncoding("utf8");
        var res_body = "";
        res.on("data", function(chunk) {
            res_body += chunk;
        });
        res.on("end", function(){
            cb(null, res_body);
        });
        res.on("error", function(err){
            cb(err);
        });
    });
    req.on("error", function(err){
        LOGGER.error("problem with request: ", err.message);
        cb(err);
    });
    req.write(contents);
    req.end();
};

/**
 * 简化http.get操作
 *
 * @param {String} url
 * @param {Function} cb
 * @example
 * self.get(url, function(err, body){
 * });
 */
Weixin.prototype.get = function(url, cb){
    HTTP.get(url, function(res){
        res.setEncoding("utf8");
        var res_body = "";
        res.on("data", function(chunk) {
            res_body += chunk;
        });
        res.on("end", function() {
            cb(null, res_body);
        });
        res.on("error", function(err){
            cb(err);
        });
    });
};